package com.ms.orm.dboperator;

import com.alibaba.fastjson.JSON;
import com.ms.common.util.ReflectUtils;
import com.ms.common.util.StringUtils;
import com.ms.orm.conditions.AbstractWrapper;
import com.ms.orm.exception.BaseSqlException;
import com.ms.orm.meta.IPage;
import com.ms.orm.meta.PropertyAndColumnInfo;
import com.ms.orm.meta.SqlAndParams;
import com.ms.orm.conditions.Wrapper;
import com.ms.orm.util.MetaDataOperator;
import com.ms.orm.util.SqlGenerator;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;

import java.io.Serializable;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;

/**
 * @author zdh
 */
public abstract class AbstractDbOperator implements DbOperator<Object> {


    protected final JdbcTemplate jdbcTemplate;
    private final Class<?> entityType;
    private final String tableName;

    public AbstractDbOperator(JdbcTemplate jdbcTemplate, Class<?> entityType, String tableName){
        this.jdbcTemplate = jdbcTemplate;
        this.entityType = entityType;
        this.tableName = tableName;
    }

    @Override
    public Object findById(Serializable id) {
        String sql = "SELECT * FROM " + tableName + " WHERE " + MetaDataOperator.getEntityIdColumnName(entityType) +" = ?";
        return jdbcTemplate.queryForObject(sql,  entityRowMapper(),new Object[]{id});
    }

    @Override
    public List<Object> findAll() {
        String sql = "SELECT * FROM " + tableName;
        return jdbcTemplate.query(sql, entityRowMapper());
    }

    @Override
    public int deleteById(Serializable id) {
       // String sql = "DELETE FROM " + tableName + " WHERE id = ?";
        String sql = "DELETE FROM " + tableName + " WHERE" + MetaDataOperator.getEntityIdColumnName(entityType) +"= ?";

       return jdbcTemplate.update(sql, id);
    }

    @Override
    public int save(Object entity) {
        // 构建SQL语句并执行保存操作
        // 这里需要根据entityType动态生成SQL语句
        SqlAndParams sqlAndParams = SqlGenerator.generateInsertSql(entity);
        return jdbcTemplate.update(sqlAndParams.getSql(), sqlAndParams.getParams().toArray());
    }

    @Override
    public int updateById(Object entity) {
        // 构建SQL语句并执行更新操作
        // 这里需要根据entityType动态生成SQL语句
        SqlAndParams sqlAndParams = SqlGenerator.generateUpdateSql(entity);
        return  jdbcTemplate.update(sqlAndParams.getSql(), sqlAndParams.getParams().toArray());
    }

    /**
     * 通过id 删除
     * @param entity 实体对象
     * @return
     */
    @Override
    public int deleteById(Object entity) {
        String sql = "DELETE FROM " + tableName + " WHERE" + MetaDataOperator.getEntityIdColumnName(entity.getClass()) +"= ?";
        //获取主键值
        Object pkValue = ReflectUtils.invokeMethod(MetaDataOperator.getEntityAndTableInfo(entity.getClass()).getPrimaryKey().getPropertyReadMethod(),entity);
        return jdbcTemplate.update(sql, pkValue);
    }

    /**
     * 通过 Map 删除
     * @param columnMap 表字段 map 对象
     * @return
     */
    @Override
    public int deleteByMap(Map<String, Object> columnMap) {
        SqlAndParams sqlAndParams = SqlGenerator.generateDeleteSqlByMap(entityType,columnMap);
        return jdbcTemplate.update(sqlAndParams.getSql(), sqlAndParams.getParams().toArray());
    }

    @Override
    public int delete(Wrapper<Object> updateWrapper) {
        SqlAndParams sqlAndParams = SqlGenerator.generateDeleteSqlByUpdateWrapper(entityType,updateWrapper);
        return jdbcTemplate.update(sqlAndParams.getSql(), sqlAndParams.getParams().toArray());
    }

    @Override
    public int deleteBatchIds(Collection<?> idList) {
        SqlAndParams sqlAndParams = SqlGenerator.generateDeleteSqlByIds(entityType,idList);
        return jdbcTemplate.update(sqlAndParams.getSql(), idList.toArray());
    }

    @Override
    public int update(Object entity, Wrapper<Object> updateWrapper) {
        SqlAndParams sqlAndParams = SqlGenerator.generateUpdateSqlByBeanAndUpdateWrapper(entityType,entity,updateWrapper);
        return jdbcTemplate.update(sqlAndParams.getSql(), sqlAndParams.getParams().toArray());
    }


    @Override
    public List<Object> selectBatchIds(Collection<? extends Serializable> idList) {
        SqlAndParams sqlAndParams = SqlGenerator.generateQuerySqlByIds(entityType,idList);
        return jdbcTemplate.query(sqlAndParams.getSql(),entityRowMapper(),idList.toArray());
    }

    @Override
    public List<Object> selectByMap(Map<String, Object> columnMap) {
        SqlAndParams sqlAndParams = SqlGenerator.generateQuerySqlByMap(entityType,columnMap);
        return jdbcTemplate.query(sqlAndParams.getSql(),entityRowMapper(),sqlAndParams.getParams().toArray());
    }

    @Override
    public Long selectCount(Wrapper<Object> queryWrapper) {
        SqlAndParams sqlAndParams = SqlGenerator.generateSelectCountSqlByWrapper(entityType,queryWrapper);
        return jdbcTemplate.queryForObject(sqlAndParams.getSql(),Long.class,sqlAndParams.getParams()!=null?sqlAndParams.getParams().toArray():null);
    }

    @Override
    public List<Object> selectList(Wrapper<Object> queryWrapper) {
        if(StringUtils.hasLength(queryWrapper.getSqlSelect())){
            return jdbcTemplate.query(queryWrapper.getFinalSql(),entityRowMapper(queryWrapper.getSqlSelect().split(",")),((AbstractWrapper<?, ?, ?>) queryWrapper).getParamNameValuePairs().values().toArray());
        }else{
            return jdbcTemplate.query(queryWrapper.getFinalSql(),entityRowMapper(),((AbstractWrapper<?, ?, ?>) queryWrapper).getParamNameValue().toArray());
        }
    }

    @Override
    public List<Map<String, Object>> selectMaps(Wrapper<Object> queryWrapper) {
        return jdbcTemplate.queryForList(queryWrapper.getFinalSql(),((AbstractWrapper<?, ?, ?>) queryWrapper).getParamNameValue().toArray());
    }

    @Override
    public  List<Object> selectOneColumnList(Wrapper<Object> queryWrapper){
        if(!StringUtils.hasLength(queryWrapper.getSqlSelect())){
            throw new BaseSqlException("【selectOneColumnList】must select one column!");
        }
        return jdbcTemplate.query(queryWrapper.getFinalSql(),oneColumnRowMapper(queryWrapper.getSqlSelect().split(",")),((AbstractWrapper<?, ?, ?>) queryWrapper).getParamNameValue().toArray());
    }

    /**
     * 根据 entity 对应数据库字段 条件，查询全部记录（分页）
     * page.current = 1 ,则查询总数，其他不再查询总数
     * @param page  分页查询
     * @param queryWrapper   实体对象封装操作类（可以为 null）
     * @param <P>
     * @return
     */
    @Override
    public <P extends IPage<Object>> P selectPage(P page, Wrapper<Object> queryWrapper){
        if(page.searchCount()){
            page.setTotal(this.selectCount(queryWrapper));
        }
        SqlAndParams sqlAndParams = SqlGenerator.generateQueryPageSqlByWrapper(page,queryWrapper);
        List<Object> recordList;
        if(StringUtils.hasLength(queryWrapper.getSqlSelect())){
            //查询指定列
            recordList = jdbcTemplate.query(sqlAndParams.getSql(),entityRowMapper(queryWrapper.getSqlSelect().split(",")),sqlAndParams.getParams().toArray());
        }else{
            recordList = jdbcTemplate.query(sqlAndParams.getSql(),entityRowMapper(),sqlAndParams.getParams().toArray());
        }
        page.setRecords(recordList!=null?recordList: Collections.emptyList());
        return page;
    }


    /**
     * 根据 Wrapper 条件，查询全部记录（并翻页）
     * @param page 分页查询条件
     * @param queryWrapper 实体对象封装操作类
     * @param <P>
     * @return
     */
    @Override
    public <P extends IPage<Map<String, Object>>> P selectMapsPage(P page,Wrapper<Object> queryWrapper){
        if(page.searchCount()){
            page.setTotal(this.selectCount(queryWrapper));
        }
        SqlAndParams sqlAndParams = SqlGenerator.generateQueryPageSqlByWrapper(page,queryWrapper);
        List<Map<String, Object>> recordList = jdbcTemplate.queryForList(sqlAndParams.getSql(),sqlAndParams.getParams().toArray());
        page.setRecords(recordList!=null?recordList: Collections.emptyList());
        return page;
    }


    /**
     * 批量插入
     * @param list
     * @return
     */
    @Override
    public int[] batchSave(List<Object> list){
        SqlAndParams sqlAndParams = SqlGenerator.generateBatchSaveSqlByList(entityType,list);
        System.err.println("【batchSave】sqlAndParams=="+JSON.toJSONString(sqlAndParams));
        return jdbcTemplate.batchUpdate(sqlAndParams.getSql(), (List<Object[]>) sqlAndParams.getParams());
    }

    /**
     * 保存或者更新，如果bean id为为空 更新
     * @param entity
     * @return
     */
    @Override
    public int saveOrUpdate(Object entity){
        return 0;
    }

    /**
     * 查询 遇到列的第一列数据
     * @return
     */
    protected RowMapper<Object> oneColumnRowMapper(String... columns) {
        return (ResultSet rs, int rowNum) -> {
            try {
                PropertyAndColumnInfo propertyAndColumnInfo = MetaDataOperator.getPropertyAndColumnInfo(entityType,columns[0]);
                Object value = DbCommonUtil.getValueByFieldFromResultSet(columns[0], propertyAndColumnInfo.getJavaType(), rs);
                return value;
            } catch (Exception e) {
                throw new RuntimeException("Error mapping row to oneColumn", e);
            }
        };
    }



    /**
     * 查询全部列数据
     * @return
     */
    protected RowMapper<Object> entityRowMapper() {
        return (ResultSet rs, int rowNum) -> {
            try {
                Object entity = entityType.getDeclaredConstructor().newInstance();
                // 假设有一个方法可以从ResultSet中填充实体属性
                populateEntityFromResultSet(entity, rs);
                return entity;
            } catch (Exception e) {
                throw new RuntimeException("Error mapping row to entity", e);
            }
        };
    }

    /**
     * 查询指定列数据
     * @param columns
     * @return
     */
    protected RowMapper<Object> entityRowMapper(String... columns) {
        return (ResultSet rs, int rowNum) -> {
            try {
                Object entity = entityType.getDeclaredConstructor().newInstance();
                // 假设有一个方法可以从ResultSet中填充实体属性
                populateEntityFromResultSet(entity, rs,columns);
                return entity;
            } catch (Exception e) {
                throw new RuntimeException("Error mapping row to entity", e);
            }
        };
    }



    /**
     * 根据entityType动态地设置实体属性
     *  需要实现这部分逻辑，可能涉及到反射或其他方式
     * @param entity
     * @param rs
     * @throws SQLException
     */
    public void populateEntityFromResultSet(Object entity, ResultSet rs) throws SQLException {
        DbCommonUtil.setObjectFromResultSetByRow(rs, entity);
    }

    /**
     * 根据entityType动态地设置实体属性
     *  需要实现这部分逻辑，可能涉及到反射或其他方式
     * @param entity
     * @param rs
     * @throws SQLException
     */
    public void populateEntityFromResultSet(Object entity, ResultSet rs,String... column) throws SQLException {
        DbCommonUtil.setObjectFromResultSetByRow(rs, entity,column);
    }
}
